package it.trekker.activities;

import java.util.Timer;
import java.util.TimerTask;
import it.trekker.R;
import it.trekker.camera.UtilityCamera;
import it.trekker.dataexchange.service.ClingDataExchangeService;
import it.trekker.dataexchange.service.IDataExchangeService;
import it.trekker.db.Excursion;
import it.trekker.db.ExcursionDAO;
import it.trekker.gps.service.GPSDataCollector;
import it.trekker.gps.service.GPSLocationService;
import it.trekker.gps.service.IGPSListener;
import it.trekker.notifications.NotificationHelper;
import it.trekker.statistics.PoiDistanceStatistics;
import it.trekker.statistics.RealTimeStatistics;
import it.trekker.wifidirect.WiFiDirectBroadcastReceiver;
import it.trekker.wifidirect.WiFiDirectConnectionInfoListener;
import it.trekker.wifidirect.WiFiDirectPeerListListener;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.TabActivity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Location;
import android.location.LocationProvider;
import android.net.Uri;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
import android.widget.Toast;

public class ExcursionMainActivity extends TabActivity implements IGPSListener {

	private static final String TAG = ExcursionMainActivity.class.getSimpleName();

	private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;

	private Uri fileUri = null;

	private String excursionName = null;
	private int excursionId;
	private boolean newExcursionStarted = false;
	private RealTimeStatistics statisticsFromStartPoint;	// Shared RealTimeStatistics (shared with RealTimeStatisticsActivity)
	private ProgressDialog progressDialog = null;
	
	// WiFi Direct
	private final IntentFilter intentFilter = new IntentFilter();
	private BroadcastReceiver receiver = null;
	private Channel channel;
	private WifiP2pManager manager;
	private WiFiDirectPeerListListener peerListener;
	private ConnectionInfoListener infoListener;
	private Timer timerSearch;

	// Service components
	private IDataExchangeService dataExchangeService;
	private GPSDataCollector gpsDataCollector;
	private GPSLocationService gpsLocationService = null;
	private ServiceConnection gpsServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			gpsLocationService.removeGPSListener(ExcursionMainActivity.this);
			gpsLocationService.removeGPSListener(gpsDataCollector);
			
			gpsLocationService = null;
			excursionName = null;
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			gpsLocationService = ((GPSLocationService.GPSBinder)service).getService();
			excursionId = gpsDataCollector.startDataCollecting(excursionName);
			statisticsFromStartPoint.setExcursionId(excursionId);
			gpsLocationService.addGPSListener(gpsDataCollector);
			gpsLocationService.addGPSListener(PoiDistanceStatistics.getSharedInstance());
			gpsLocationService.addGPSListener(ExcursionMainActivity.this);
		}
	};
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.excursions_main_layout);

		// Shared RealTimeStatistics (shared with RealTimeStatisticsActivity) 
		statisticsFromStartPoint = RealTimeStatistics.getSharedInstance();

		TabHost tabHost = getTabHost();
		TabSpec spec;
		Intent intent;

		// Tab for Statistics
		spec = tabHost.newTabSpec("Statistics");
		spec.setIndicator("Statistics", getResources().getDrawable(R.drawable.statistics_icon));
		intent = new Intent(this, RealTimeStatisticsActivity.class);
		intent.putExtra("realtime_statistics", statisticsFromStartPoint);
		spec.setContent(intent);
		tabHost.addTab(spec); // Adding statistics tab

		// Tab for Map
		spec = tabHost.newTabSpec("Map");
		spec.setIndicator("Map", getResources().getDrawable(R.drawable.map_icon));
		intent = new Intent(this, RealTimeMapActivity.class);
		//        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		spec.setContent(intent);
		tabHost.addTab(spec); // Adding map tab
		
		// Tab for Pois
		spec = tabHost.newTabSpec("Pois");
		spec.setIndicator("Pois", getResources().getDrawable(R.drawable.poi_icon));
		intent = new Intent(this, DistanceToPoiActivity.class);
		spec.setContent(intent);
		tabHost.addTab(spec); // Adding pois tab

		tabHost.setCurrentTab(0);

		gpsDataCollector = new GPSDataCollector(this);

		if(savedInstanceState != null && savedInstanceState.containsKey("newExcursionStarted")) {
			newExcursionStarted = savedInstanceState.getBoolean("newExcursionStarted");
		}

		if(savedInstanceState == null || newExcursionStarted == false) {
			Bundle extras = getIntent().getExtras();
			if(extras.containsKey("excursion_name")) {
				excursionName = extras.getString("excursion_name");
				statisticsFromStartPoint.setExcursionName(excursionName);
				startExcursion();
			}
		}

		checkGpsStatus();
		
		lookingForGpsSignal();
//		Thread thread = new Thread(this);
//		thread.start();

		NotificationHelper.buildNotification(this);
		

		// WiFiDirect

		intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
		intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
		intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
		intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

		manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
		channel = manager.initialize(this, getMainLooper(), null);

		peerListener = new WiFiDirectPeerListListener(this, manager, channel);
		infoListener = new WiFiDirectConnectionInfoListener();
		
		receiver = new WiFiDirectBroadcastReceiver(manager, channel, peerListener, infoListener);
		registerReceiver(receiver, intentFilter);
		
		timerSearch = new Timer();
		timerSearch.scheduleAtFixedRate(createTimerTaskSearch(), 0, 1000);
		
		// Start data exchange service
		
		SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
		boolean startClient = sharedPref.getBoolean("upnp_client_enable", true);
		boolean startServer = sharedPref.getBoolean("upnp_server_enable", true);
		int searchingInterval = Integer.parseInt(sharedPref.getString("upnp_searching_interval", "2000"));
		dataExchangeService = ClingDataExchangeService.getInstanceAndCreateIfNotExist(getApplicationContext(), PoiDistanceStatistics.getSharedInstance());
		dataExchangeService.setSearchingInterval(searchingInterval);
		dataExchangeService.startUPnP(startServer, startClient);
	}
	
	
	private TimerTask createTimerTaskSearch() {
		return new TimerTask() {
			
			@Override
			public void run() {
				manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {

                    @Override
                    public void onSuccess() {
                    }

                    @Override
                    public void onFailure(int reasonCode) {
                    }
                });
			}
		};
	}
	
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		
		if(timerSearch != null)
			timerSearch.cancel();
		
		if(receiver != null)
			unregisterReceiver(receiver);
		
		if(newExcursionStarted) {
			stopExcursion();
		}
		
	}


	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		Log.d(TAG, "onSaveInstanceState");
		

		outState.putBoolean("newExcursionStarted", newExcursionStarted);
		outState.putString("excursion_name", excursionName);
		outState.putInt("excursion_id", excursionId);
	}
	

	//	@Override
	//	protected void onRestoreInstanceState(Bundle state) {
	//		super.onRestoreInstanceState(state);
	//
	//		Log.d(TAG, "onRestoreInstanceState");
	//
	//		newExcursionStarted = state.getBoolean("newExcursionStarted");
	//	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);

		Log.d(TAG, "onConfigurationChanged");
	}
	

	@Override
	public void onBackPressed() {
		Log.d(TAG, "Back pressed");

		if(newExcursionStarted) {
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setMessage("An excursion is in progress: do you want stop it?")
			.setCancelable(false)
			.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int id) {
					stopExcursion();
					if(gpsLocationService != null) {
						gpsLocationService.removeGPSListener(ExcursionMainActivity.this);
						gpsLocationService.removeGPSListener(gpsDataCollector);
					}
					ExcursionMainActivity.this.finish();
					launchExcursionStatisticsActivity();
				}
			})
			.setNegativeButton("No", new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});
			AlertDialog alert = builder.create();
			alert.show();
		}
		else {
			super.onBackPressed();
		}

	}


	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
			if (resultCode == RESULT_OK) {
				if(statisticsFromStartPoint.isGpsEnabled()) {	// For the real device
//				if(true) {	// For test with emulator
					// Image captured and saved to fileUri specified in the Intent
					Toast.makeText(this, "Image saved to:\n" + fileUri, Toast.LENGTH_LONG).show();
					Location location = statisticsFromStartPoint.getCurrentLocation();
					UtilityCamera.storeGeotagInfo(fileUri.getPath(), location.getLatitude(), location.getLongitude());
					UtilityCamera.deleteImageFromDCIM(this, fileUri.getPath());
					UtilityCamera.updateGallery(this);

					// Save photo into database
					UtilityCamera.savePhotoIntoDatabase(this, excursionId, fileUri, location);
//					PhotoDAO photoDAO = new PhotoDAO(this);
//					photoDAO.open();
//					Photo photo = new Photo(fileUri.getPath(), excursionId);
//					photo.setLatitude(location.getLatitude());
//					photo.setLongitude(location.getLongitude());
//					photo.setId(photoDAO.insertPhoto(photo));
//					photoDAO.close();
				}
				else {
					Toast.makeText(this, "GPS not available: image saved in the default gallery", Toast.LENGTH_LONG).show();
				}
			} 
			else if (resultCode == RESULT_CANCELED) {
				Toast.makeText(this, "Operation aborted", Toast.LENGTH_LONG).show();
			} 
			else {
				Toast.makeText(this, "Failed to take photo", Toast.LENGTH_LONG).show();
			}
		}
		else {
			super.onActivityResult(requestCode, resultCode, data);
		}
	}




	//*****************************************************************//
	//*********************** Utility functions ***********************//
	//*****************************************************************//

	public int getExcursionId() {
		return excursionId;
	}

	
	private void startExcursion() {
		Intent gpsIntent = new Intent(this, GPSLocationService.class);
		getApplicationContext().bindService(gpsIntent, gpsServiceConnection, Context.BIND_AUTO_CREATE);

		newExcursionStarted = true;
	}

	
	private void stopExcursion() {
		gpsDataCollector.stopDataCollecting();
		gpsLocationService.removeGPSListener(gpsDataCollector);

		getApplicationContext().unbindService(gpsServiceConnection);
		
		dataExchangeService.stopUPnP();

		newExcursionStarted = false;

		updateExcursion();

		statisticsFromStartPoint.invalidateSharedInstance();
		PoiDistanceStatistics.getSharedInstance().invalidateSharedInstance();

		NotificationHelper.removeNotification(this);
	}

	
	private void updateExcursion() {

		ExcursionDAO excursionDAO = new ExcursionDAO(this);
		excursionDAO.open();
		Excursion excursion = excursionDAO.getExcursion(excursionId);
		if(excursion != null) {
			excursion.setSteps(statisticsFromStartPoint.getSteps());
			excursion.setDistance(statisticsFromStartPoint.getDistance());
			excursion.setMeanPace(statisticsFromStartPoint.getMeanPace());
			excursion.setTotAltitudeDifference(statisticsFromStartPoint.getTotAltitudeDifference());
			excursion.setTime(statisticsFromStartPoint.getTime());
			
			excursionDAO.updateExcursion(excursion);
		}
		excursionDAO.close();
	}

	private void launchExcursionStatisticsActivity() {
		Intent intent;

		intent = new Intent(this, ExcursionStatisticsActivity.class);
		intent.putExtra("excursion_id", excursionId);
		startActivity(intent);
	}

	private void takePhoto() {
		fileUri = UtilityCamera.getOutputMediaFileUri(UtilityCamera.MEDIA_TYPE_IMAGE); // create a file to save the image

		if(!UtilityCamera.launchCamera(this, fileUri, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE)) {
			Toast.makeText(this, "Unable to create file", Toast.LENGTH_LONG).show();
		}
	}





	//***********************************************************//
	//*********************** Option Menu ***********************//
	//***********************************************************//

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.clear();
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.excursion_main_menu, menu);

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {

		case R.id.stop_excursion:
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setMessage("Do you really want stop this excursion?")
			.setCancelable(false)
			.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int id) {
					stopExcursion();
					if(gpsLocationService != null) {
						gpsLocationService.removeGPSListener(ExcursionMainActivity.this);
						gpsLocationService.removeGPSListener(gpsDataCollector);
					}
					ExcursionMainActivity.this.finish();
					launchExcursionStatisticsActivity();
				}
			})
			.setNegativeButton("No", new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});
			AlertDialog alert = builder.create();
			alert.show();
			return true;

		case R.id.take_photo:
			takePhoto();
			return true;

		default:
			return super.onOptionsItemSelected(item);
		}
	}



	//*******************************************************************//
	//************************* Looking for GPS *************************//
	//*******************************************************************//

	private void checkGpsStatus() {
		String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);

		if(!provider.contains("gps")){ //if gps is disabled
			final Intent poke = new Intent();
			poke.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider"); 
			poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
			poke.setData(Uri.parse("3")); 
			sendBroadcast(poke);
		}
	}

	private void lookingForGpsSignal() {
		progressDialog = ProgressDialog.show(this, "Searching..." , "Looking for GPS signal");
		progressDialog.setCancelable(true);
	}

	private void gpsSignalFound() {
		progressDialog.dismiss();
	}



//	private static final int GPS_LOST = 0;
//	private static final int GPS_FOUND = 1;
//	@Override
//	public void run() {
//		try {
//			wait();
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//	}
//
//	private Handler handler = new Handler() {
//		@Override
//		public void handleMessage(Message msg) {
//			switch(msg.what) {
//			case GPS_LOST:
//				lookingForGpsSignal();
//				break;
//			case GPS_FOUND:
//				gpsSignalFound();
//				break;
//			default:
//				super.handleMessage(msg);
//				break;
//			}
//		};
//	};

	@Override
	public void onLocationChanged(Location location) {
	}

	@Override
	public void onProviderDisabled() {
	}

	@Override
	public void onProviderEnabled() {
	}

	@Override
	public void onStatusChanged(int status) {
		if(status == LocationProvider.AVAILABLE) {
//			handler.sendEmptyMessage(GPS_FOUND);
			gpsSignalFound();
		}
		else {
//			handler.sendEmptyMessage(GPS_LOST);
			lookingForGpsSignal();
		}
	}




}
